/*******************************************************************\
| MathBase.h
|
|--------------------------------------------------------------------
| Copyright 2005. Martin Fleisz.
| All rights reserved.
|
|--------------------------------------------------------------------
| CREATED:		2006/2/20
| AUTHOR:		Martin Fleisz
|
|--------------------------------------------------------------------
| DESCRIPTION:
| 
| Contains basic math functions and constants
\********************************************************************/
#ifndef MATHBASE_H
#define MATHBASE_H

#include <cmath>

namespace Math
{

// common math constants
const float PI			= 3.141592653589793238462643383279502884197f;	// PI constant
const float PIHalf		= 1.570796326794896619231321691639751442099f;	// PI / 2
const float DivPI180	= 0.01745329251994329576923690768488612713443f;	// PI / 180
const float Div180PI	= 57.29577951308232087679815481410517033241f;	// 180 / PI
const float Inv2PI		= 0.15915494309189533576888376337251f;			// 1 / (2 * PI)
const float EPSILON		= 0.001f;										// minimum value for floats
const float INFINITY	= 3.4e+38f;										// big float number

// convert degrees to radians
inline float DegToRad(float p_Value)
{
	return p_Value * DivPI180;
}

// convert radians to degrees
inline float RadToDeg(float p_Value)
{
	return p_Value * Div180PI;
}

// p_Value^2
template <class T>
inline T Sqr(T p_Value) 
{
	return (p_Value * p_Value);
}

// p_Value^3
template <class T>
inline T Cube(T p_Value) 
{
	return (p_Value * p_Value * p_Value);
}

// absolute function for floats
inline float Abs(float p_Value) 
{
	(*(long*)&p_Value) &= 0x7fffffff;
	return p_Value;
}

// returns true if the value is zero
template<class _Type>
inline bool IsZero(_Type p_Val)
{
	return Abs(p_Val) < EPSILON;
}

// fast reciprocal square root
inline float InvSqrt(float p_Value)
{
	union
	{
		int intPart;
		float floatPart;
	}Converter;

	Converter.floatPart = p_Value;	
	Converter.intPart = 0x5f3759df - (Converter.intPart >> 1);	
	return 0.5f * Converter.floatPart * (3.0f - p_Value * Converter.floatPart * Converter.floatPart);
}

// p_Value^pow
inline float Pow(float p_Value, float p_Power) 
{
	return powf(p_Value, p_Power);
}

// square-root
inline float Sqrt(float p_Value)
{	
	return sqrtf(p_Value);
}

// Exponential
inline float Exp(float p_Value)
{	
	return expf(p_Value);
}

// Log10
inline float Log10(float p_Value)
{		
	return log10f(p_Value);
}

// Get mantissa and exponent of a float
inline float FRExp(float p_Value, int* p_ExpPtr)
{	
	return frexpf(p_Value, p_ExpPtr);
}

// computes a float number from mantissa and exponent
inline float LDExp(float p_Value, int p_Exp)
{	
	return ldexpf(p_Value, p_Exp);
}

// max
template<typename _Type>
inline _Type Max(const _Type p_Val1, const _Type p_Val2)
{
	return (((p_Val1) > (p_Val2)) ? (p_Val1) : (p_Val2));
}

// max
template<typename _Type>
inline _Type Min(const _Type p_Val1, const _Type p_Val2)
{
	return (((p_Val1) < (p_Val2)) ? (p_Val1) : (p_Val2));
}

//******************************************************************************//
// Trigonometric functions

// return Sin(v)
inline float Sin(float p_Value)
{		
	return sinf(p_Value);
}

// return Cos(v)
inline float Cos(float p_Value)
{		
	return cosf(p_Value);
}

// return ACos(v)
inline float ACos(float p_Value)
{		
	return acosf(p_Value);
}

// return sin( r ) / cos( r );
inline float Tan(float p_Value)
{		
	return tanf(p_Value);
}

// Atan2
inline float ATan2(float p_X, float p_Y)
{		
	return atan2f(p_X, p_Y);
}

// return sin( r ) / cos( r );
inline float Cot(float p_Value)
{
	return 1.0f / tanf(p_Value);		
}

// interpolates between two values
template<class T>
inline T Interpolate(const T p_Val1, const T p_Val2, const T p_Factor)
{
	return p_Val1 * (1.0f - p_Factor) + p_Val2 * p_Factor;
}

// clamps a value
template<class T>
inline T Clamp(const T p_Val, const T p_LowerBound, const T p_UpperBound)
{
	if(p_Val <= p_LowerBound)	return p_LowerBound;
	if(p_Val >= p_UpperBound)	return p_UpperBound;
	return p_Val;
}

// random function (srand must be called before using this function)
inline float Random(const float p_MaxRand)
{
	return ((p_MaxRand / RAND_MAX) * rand());
}

} // namespace Math

#endif // MATHBASE_H
